package jmine.tec.web.servlet;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

import bancosys.tec.utils.reflection.ReflectionUtils;

import jmine.tec.web.servlet.util.ServletExecutor;

/**
 * @author takeshi
 */
public class LazyInitializingServlet extends HttpServlet {

    private volatile HttpServlet servlet = new WebContextResourceServlet();

    private Future<?> future;

    private String servletClassName;

    /**
     * {@inheritDoc}
     */
    public void destroy() {
        getServlet().destroy();
        synchronized (this.getServletContext()) {
            if (this.future != null) {
                this.future.cancel(true);
            }
        }
        ServletExecutor.shutdownExecutorServices(getServletContext(), false);
    }

    /**
     * {@inheritDoc}
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.servletClassName = config.getInitParameter("servletClassName");
        if (servletClassName == null) {
            throw new IllegalStateException("servletClassName was not supplied");
        }
        // now we need a bunch of things
        ExecutorService executorService = ServletExecutor.getOrCreateExecutorService(config.getServletContext());
        getServlet().init(config);
        try {
            @SuppressWarnings("unchecked")
            Class<? extends HttpServlet> servletClass = (Class<? extends HttpServlet>) ReflectionUtils.findClass(servletClassName);
            HttpServlet instance = servletClass.getConstructor().newInstance();
            this.future = executorService.submit(new InitializerTask(instance));
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        getServlet().service(req, res);
    }

    /**
     * @return the {@link HttpServlet}
     */
    private HttpServlet getServlet() {
        return servlet;
    }

    /**
     * Inicializa e coloca no campo {@link LazyInitializingServlet#servlet} o servlet
     * 
     * @author takeshi
     */
    private class InitializerTask implements Runnable {

        private final HttpServlet servletInstance;

        /**
         * @param servletInstance {@link HttpServlet}
         */
        public InitializerTask(HttpServlet servletInstance) {
            super();
            this.servletInstance = servletInstance;
        }

        /**
         * {@inheritDoc}
         */
        public void run() {
            try {
                servletInstance.init(getServletConfig());
                servlet = servletInstance;
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }

    }

}
